【精选】使用Android Studio模板插件创建MVP项目

您所在的位置:网站首页 项目 mvp 【精选】使用Android Studio模板插件创建MVP项目

【精选】使用Android Studio模板插件创建MVP项目

2023-11-11 03:45| 来源: 网络整理| 查看: 265

文章目录 Android MVP Template序添加wizard-template.jar修改build.gradle.kts修改gradle.properties修改setting.gradle.kts改造 ***listeners/MyProjectManagerListener.kt***接下来在src/main/kotlin目录下创建other,其他包和文件的目录结构如下以Activity为例,为创建的文件注入灵魂实现 WizardTemplateProvider为mvpActivityTemplate.kt 注入灵魂为mvpActivityRecipe.kt 注入灵魂为mvpBaseView.kt注入灵魂为mvpBasePresenter.kt注入灵魂为mvpContract.kt注入灵魂为mvpPresenter.kt注入灵魂为mvpActivity.kt注入灵魂接下来就是为布局文件layout注入灵魂修改 src/main/resources/META-INF/plugin.xml 遗留问题写在后面的话

Android MVP Template 序

今天是在项目的时候频繁创建mvp架构的类,突然想到之前用到的AndroidLiveTemplate模板,于是就想写一个模板一键创建, 于是乎就去安装目录下寻找相关的模板文件夹,找了半天发现原来的那套freemarker的那套模板引擎被和谐了,网上翻阅了资料才发现 从Android4.1开始,Android live template的方式已经被Google和谐了,最近刚好是项目有这个需要,所以从新整理一下官方文档,也参考了一些网友的总结,再结合我项目MVP的架构,写了一个插件

这是一个AndroidStudio的插件,使用的是intellij官方开源的intellij platform plugin template 我在这里就不对这个项目的结构以及详细的api进行讲解,如果有需要的小伙伴可以移步查询,本文档直接从项目源码进行改造成我们想要的template开始

添加wizard-template.jar

首先我们下载了intellij官方模板之后,我们首先在项目的根目录下创建一个lib目录,然后在AndroidStudio的安装目录下面找到wizard-template.jar,windows电脑该文件在Android Studio\plugins\android\lib\ 目录下,MacOS系统的话在Applications/Android Studio.app/Contents/plugins/android/lib/目录下, 找到这个文件之后将其复制到新建的lib目录下面

修改build.gradle.kts

添加依赖

dependencies { detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.17.1") compileOnly(files("lib/wizard-template.jar")) // 添加这一行 } 修改gradle.properties

这里我们需要修改的地方分别是如下四处

字段是否必须要修改原始值修改后的值pluginGroupxorg.jetbrains.plugins.templatecom.neo.mvp.templatepluginNamexIntelliJ Platform Plugin TemplateMVP TemplateplatformVersionx0.10.10.0.1platformPlugins√Kotlin,com.intellij.java,org.jetbrains.android, android, org.jetbrains.kotlin

这其中有三个不是必须要修改的,不该也不影响后续的开发,不多还是建议结合自己项目修改一下这些配置

修改setting.gradle.kts rootProject.name = "MVP Template"

接下来对项目代码的编写,如果你修改了gradle.properties里的所pluginGroup属性的值,接下来你需要对 src/main/kotlin/ 目录下的包路径修改成对应的包名

改造 listeners/MyProjectManagerListener.kt

管理着项目的生命周期的监听

internal class MyProjectManagerListener : ProjectManagerListener { private var projectInstance: Project? = null override fun projectOpened(project: Project) { projectInstance = project project.getService(MyProjectService::class.java) } override fun projectClosing(project: Project) { projectInstance = null super.projectClosing(project) } } 接下来在src/main/kotlin目录下创建other,其他包和文件的目录结构如下 ├──src ├ └──main ├ └──kotlin ├ └──other ├ └──mvp ├ └──SimplePluginTemplateProviderImpl.kt ├ └──activity ├ └──res.layout ├ └──mvpActivityXml.kt ├ └──src.app_package ├ └──contract ├ └──mvpContract.kt ├ └──p ├ └──mvpPresenter.kt ├ └──v ├ └──mvpActivity.kt ├ └──mvpBasePresenter.kt ├ └──mvpBaseView.kt ├ └──mvpActivityRecipe.kt ├ └──mvpActivityTemplate.kt 以Activity为例,为创建的文件注入灵魂 实现 WizardTemplateProvider

MVPTemplateProviderImpl.kt

package other.mvp import com.android.tools.idea.wizard.template.Template import com.android.tools.idea.wizard.template.WizardTemplateProvider import other.mvp.activity.mvpActivityTemplate /** * @Author Neo * @Date 2021/6/7 * @Env Viicare-Neo * @Description SamplePluginTemplateProviderImpl */ class MVPTemplateProviderImpl: WizardTemplateProvider() { override fun getTemplates(): List { return listOf( // activity 模板 mvpActivityTemplate ) } } 为mvpActivityTemplate.kt 注入灵魂

这个文件是设置在创建Activity的时候,输入的信息, 例如 ActivityName,layoutName, packageName

package other.mvp.activity import com.android.tools.idea.wizard.template.* import com.android.tools.idea.wizard.template.impl.activities.common.MIN_API /** * @Author Neo * @Date 2021/6/7 * @Env Viicare-Neo * @Description mvpActivityTemplate * 这个文件是设置在创建Activity的时候,输入的信息, * 例如 ActivityName,layoutName, packageName */ val mvpActivityTemplate get() = template { revision = 1 name = "MVP Activity" description = "适用于MVP框架的Activity" minApi = MIN_API minBuildApi = MIN_API category = Category.Other formFactor = FormFactor.Mobile screens = listOf(WizardUiContext.ActivityGallery, WizardUiContext.MenuEntry, WizardUiContext.NewProject, WizardUiContext.NewModule) lateinit var layoutName: StringParameter val activityClass = stringParameter { name = "Activity Name" default = "Main" help = "只输入名字,不要包含Activity" constraints = listOf(Constraint.NONEMPTY) } layoutName = stringParameter { name = "Layout Name" default = "activity_main" help = "请输入布局的名字" constraints = listOf(Constraint.LAYOUT, Constraint.UNIQUE, Constraint.NONEMPTY) suggest = { activityToLayout(activityClass.value.toLowerCase()) } } val packageName = defaultPackageNameParameter widgets( TextFieldWidget(activityClass), TextFieldWidget(layoutName), PackageNameWidget(packageName) ) // thumb { File("logo.png") } recipe = { data: TemplateData -> mvpActivityRecipe( data as ModuleTemplateData, activityClass.value, layoutName.value, packageName.value) } } val defaultPackageNameParameter get() = stringParameter { name = "Package name" visible = { !isNewModule } default = "com.neo.myapp" constraints = listOf(Constraint.PACKAGE) suggest = { packageName } } 为mvpActivityRecipe.kt 注入灵魂

这个类是处理按照模板创建项目文件并保存的,我们再创建other.mvp.*下面的文件路径是可以任意的, 实际创建的文件包路径都是在这个文件的save方法中决定

package other.mvp.activity import com.android.tools.idea.wizard.template.ModuleTemplateData import com.android.tools.idea.wizard.template.RecipeExecutor import other.mvp.activity.res.layout.mvpActivityXml import other.mvp.activity.src.app_package.contract.mvpContract import other.mvp.activity.src.app_package.mvpBasePresenter import other.mvp.activity.src.app_package.mvpBaseView import other.mvp.activity.src.app_package.p.mvpPresenter import other.mvp.activity.src.app_package.v.mvpActivityKt /** * @Author Neo * @Date 2021/6/7 * @Env Viicare-Neo * @Description mvpActivityRecipe 这个文件用于将创建的文件保存到文件夹中,例如Activity,布局文件等 */ fun RecipeExecutor.mvpActivityRecipe( moduleData: ModuleTemplateData, activityClass: String, layoutName: String, packageName: String ) { val (projectData, srcOut, resOut) = moduleData val ktOrJavaExt = projectData.language.extension val mvpActivity = mvpActivityKt(packageName, activityClass, layoutName, packageName) // 保存Activity save(mvpActivity, srcOut.resolve("v/${activityClass}Activity.${ktOrJavaExt}")) // 保存xml save(mvpActivityXml(packageName, activityClass), resOut.resolve("layout/${layoutName}.xml")) try { // 判断BaseView类是否存在,如果不存在则创建保存 val forName = Class.forName("${packageName}.BaseView") } catch (e: Exception) { save(mvpBaseView(packageName), srcOut.resolve("BaseView.${ktOrJavaExt}")) } try { // 判断BasePresenter类是否存在,如果不存在则创建保存 val forName = Class.forName("${packageName}.BasePresenter") } catch (e: Exception) { save(mvpBasePresenter(packageName), srcOut.resolve("BasePresenter.${ktOrJavaExt}")) } // 保存Contract save(mvpContract(packageName,activityClass), srcOut.resolve("contract/${activityClass}Contract.${ktOrJavaExt}")) // 保存Presenter save(mvpPresenter(packageName,packageName,activityClass), srcOut.resolve("p/${activityClass}Presenter.${ktOrJavaExt}")) } 为mvpBaseView.kt注入灵魂

这个是我项目中mvp架构的view底层类

package other.mvp.activity.src.app_package /** * @Author Neo * @Date 2021/6/8 * @Env Viicare-Neo * @Description mvpBaseView */ fun mvpBaseView( packageName: String ) = """ package $packageName interface BaseView

{ fun setPresenter(p:P) } """ 为mvpBasePresenter.kt注入灵魂

这个是我项目中mvp架构的presenter底层类

package other.mvp.activity.src.app_package /** * @Author Neo * @Date 2021/6/8 * @Env Viicare-Neo * @Description mvpBasePresenter */ fun mvpBasePresenter( packageName:String )=""" package $packageName interface BasePresenter { fun subscribe() fun unSubscribe() } """ 为mvpContract.kt注入灵魂

这个是我项目mvp架构中针对不同activity进行注册v,p两层处理方法的接口

package other.mvp.activity.src.app_package.contract /** * @Author Neo * @Date 2021/6/8 * @Env Viicare-Neo * @Description mvpContract */ fun mvpContract( packageName:String, activityName:String )=""" package $packageName.contract import ${packageName}.BaseView import ${packageName}.BasePresenter interface ${activityName}Contract { interface View: BaseView { } interface Presenter: BasePresenter { } } """ 为mvpPresenter.kt注入灵魂

这个是我项目mvp架构中针对不同activity进行P端代码的具体实现类

package other.mvp.activity.src.app_package.p /** * @Author Neo * @Date 2021/6/8 * @Env Viicare-Neo * @Description mvpPresenter */ fun mvpPresenter ( applicationPackage: String?, packageName:String, activityClass: String )=""" package $packageName.p import ${applicationPackage}.contract.${activityClass}Contract class ${activityClass}Presenter(private val mView: ${activityClass}Contract.View): ${activityClass}Contract.Presenter { init { // TODO something mView.setPresenter(this) } override fun subscribe() { } override fun unSubscribe() { } } """ 为mvpActivity.kt注入灵魂

这个是我项目中页面activity

package other.mvp.activity.src.app_package.v /** * @Author Neo * @Date 2021/6/7 * @Env Viicare-Neo * @Description mvpActivityKt */ fun mvpActivityKt ( applicationPackage: String?, activityClass: String, layoutName: String, packageName: String )=""" package $packageName.v import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import ${applicationPackage}.p.${activityClass}Presenter import ${applicationPackage}.contract.${activityClass}Contract class ${activityClass}Activity : AppCompatActivity (),${activityClass}Contract.View { private lateinit var mPresenter: ${activityClass}Contract.Presenter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.${layoutName}) // TODO something ${activityClass}Presenter(this) } override fun setPresenter (p: ${activityClass}Contract.Presenter) { this.mPresenter = p this.mPresenter.subscribe() } } """ 接下来就是为布局文件layout注入灵魂

决定此布局文件的类是res/layout/mvpActivityXml.kt

package other.mvp.activity.res.layout /** * @Author Neo * @Date 2021/6/7 * @Env Viicare-Neo * @Description mvpActivityXml */ fun mvpActivityXml(packageName: String, activityClass: String )="""


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3